package com.kf.service.Impl;

import cn.hutool.http.HttpResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kf.pojo.LogError;
import com.kf.mapper.LogErrorMapper;
import com.kf.service.LogErrorService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kf.thread.DownloadExcelRunnable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 异常日志 服务实现类
 * </p>
 *
 * @author 康峰
 * @since 2022-11-09
 */
@Service
public class LogErrorServiceImpl extends ServiceImpl<LogErrorMapper, LogError> implements LogErrorService {

    @Autowired
    LogErrorMapper logErrorMapper;

    private static final String FilePath = System.getProperty("java.io.tmpdir") + File.separator;

    @Override
    public IPage<LogError> pageLogError(String name, int current, int size) {
        Page<LogError> logErrorPage= new Page<>(current, size);
        logErrorPage.setDesc("id");
        QueryWrapper<LogError> logErrorQueryWrapper = new QueryWrapper<>();
        logErrorQueryWrapper.like("request_user",name);
        return logErrorMapper.selectPage(logErrorPage, logErrorQueryWrapper);
    }


    @Override
    public void exports(HttpServletResponse response,String tmpFileName) {
        long startTime = System.currentTimeMillis();
        // 用于存放文件路径
        List<String> filePaths = new ArrayList<>();
        //生成的ZIP文件名为Demo.zip
//        String tmpFileName = "雇员信息表.zip";
        // zip文件路径
        String strZipPath = FilePath + tmpFileName;
        filePaths.add(strZipPath);
        try {
            //创建zip输出流
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(strZipPath));
            //声明文件集合用于存放excel文件
            List<File> fileList = new ArrayList<File>();
            //生成excel文件集合
            //总记录数
            int total = this.count(null);
            int pageSize = 100000;
            //总页码数
            int totalPage = total / pageSize + (total % pageSize == 0 ? 0 : 1);
            ExecutorService executorService = Executors.newFixedThreadPool(totalPage);

            for (int i = 0; i < totalPage; i++) {
                //2、这里传入的参数是Runnable接口实现类的对象，并调用execute()方法
                // 生成随机文件名
                String filename = FilePath + "雇员信息表" + i + ".xls";
                // 将文件路径保存
                File file = new File(filename);
                fileList.add(file);
                filePaths.add(filename);
                executorService.execute(new DownloadExcelRunnable(i, pageSize, file, logErrorMapper));
            }
            //        //3、关闭线程池
            executorService.shutdown();
            //等待所有任务都执行结束
            while (true) {
                //所有的子线程都结束了
                if (executorService.isTerminated()) {
                    break;
                }
            }

            byte[] buffer = new byte[1024];
            //将excel文件放入zip压缩包
            for (int i = 0; i < fileList.size(); i++) {
                File file = fileList.get(i);
                FileInputStream fis = new FileInputStream(file);
                out.putNextEntry(new ZipEntry(file.getName()));
                int len;
                // 读入需要下载的文件的内容，打包到zip文件
                while ((len = fis.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                out.closeEntry();
                fis.close();
            }
            out.close();
            //下载zip文件
            this.downFile(response, tmpFileName, filePaths);
        } catch (Exception e) {
            // 下载失败删除生成的文件
            deleteFile(filePaths);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("EmployeeServiceImpl.downloadExcel2(),总计耗时:" + (endTime - startTime)+"毫秒");
    }

    //删除文件
    public static boolean deleteFile(List<String> filePath) {
        boolean result = false;
        for (String pathname : filePath) {
            File file = new File(pathname);
            if (file.exists()) {
                file.delete();
                result = true;
            }
        }
        return result;
    }

    /**
     * 文件下载
     *
     * @param response
     * @param str
     * @param filePaths
     */
    private void downFile(HttpServletResponse response, String str, List<String> filePaths) {
        try {
            String path = FilePath + str;
            File file = new File(path);
            if (file.exists()) {
                InputStream ins = new FileInputStream(path);
                BufferedInputStream bins = new BufferedInputStream(ins);// 放到缓冲流里面
                OutputStream outs = response.getOutputStream();// 获取文件输出IO流
                BufferedOutputStream bouts = new BufferedOutputStream(outs);
//                response.setContentType("application/x-download");// 设置response内容的类型
                response.setHeader(
                        "Content-Disposition",
                        "attachment;filename="
                                + URLEncoder.encode(str, "UTF-8"));// 设置头部信息

//                response.addHeader("Content-Disposition", "attachment;filename=" +new String((fileForm.getFilename()+"."+ fileForm.getSuffix()).getBytes("UTF-8"),"ISO-8859-1"));

                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                // 开始向网络传输文件流
                while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {
                    bouts.write(buffer, 0, bytesRead);
                }
                bouts.flush();// 这里一定要调用flush()方法
                ins.close();
                bins.close();
                outs.close();
                bouts.close();
                deleteFile(filePaths);
            }
        } catch (IOException e) {
            deleteFile(filePaths);
        }
    }
}
